/**
 *  Copyright (C) 2006 zhangbo (freeeob@gmail.com)
 *
 *  This product is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 * 
 *  This product is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 *
 *  author:zhangbo
 *  Email:jsjava@gmail.com
 */

/**  The Gamma class references to org.apache.commons.math.special.Beta */

function Beta(){
	this.jsjava_class="org.apache.commons.math.special.Beta";
}

Beta.DEFAULT_EPSILON = 10e-9;

/**
 * Returns the regularized beta function I(x, a, b).
 * @param x the value
 * @param a the a parameter.
 * @param b the b parameter.
 */
Beta.regularizedBeta=function(x,a,b){
	return Beta.regularizedBeta4(x, a, b, Beta.DEFAULT_EPSILON, Integer.MAX_VALUE);
};

/**
 * Returns the regularized beta function I(x, a, b).
 * @param x the value
 * @param a the a parameter.
 * @param b the b parameter.
 * @param epsilon When the absolute value of the nth item in the series is less than 
 * epsilon the approximation ceases to calculate further elements in the series. 
 */
Beta.regularizedBeta2=function(x,a,b,epsilon){
	return Beta.regularizedBeta4(x, a, b, epsilon, Integer.MAX_VALUE);
};

/**
 * Returns the regularized beta function I(x, a, b).
 * @param x the value
 * @param a the a parameter.
 * @param b the b parameter.
 * @param maxIterations Maximum number of "iterations" to complete.
 */
Beta.regularizedBeta3=function(x,a,b,maxIterations){
	return Beta.regularizedBeta4(x, a, b, Beta.DEFAULT_EPSILON, maxIterations);
};

/**
 * Returns the regularized beta function I(x, a, b).
 * @param x the value
 * @param a the a parameter.
 * @param b the b parameter.
 * @param epsilon When the absolute value of the nth item in the series is less than 
 * epsilon the approximation ceases to calculate further elements in the series.
 * @param maxIterations Maximum number of "iterations" to complete.
 */
Beta.regularizedBeta4=function(x,a,b,epsilon,maxIterations){
	function ContinuedFraction(){
		
	}
	ContinuedFraction.DEFAULT_EPSILON = 10e-9;
	ContinuedFraction.prototype.evaluate=function(x){
		return this.evaluate(x, ContinuedFraction.DEFAULT_EPSILON, Integer.MAX_VALUE);
	};
	ContinuedFraction.prototype.evaluate2=function(x,epsilon){
		return this.evaluate(x, epsilon, Integer.MAX_VALUE);
	};
	ContinuedFraction.prototype.evaluate3=function(x,maxIterations){
		return this.evaluate(x, ContinuedFraction.DEFAULT_EPSILON, maxIterations);
	};
	ContinuedFraction.prototype.evaluate4=function(x,epsilon,maxIterations){
		var p0 = 1.0;
        var p1 = this.getA(0, x);
        var q0 = 0.0;
        var q1 = 1.0;
        var c = p1 / q1;
        var n = 0;
        var relativeError = Double.MAX_VALUE;
        while (n < maxIterations && relativeError > epsilon) {
            ++n;
            var a = this.getA(n, x);
            var b = this.getB(n, x);
            var p2 = a * p1 + b * p0;
            var q2 = a * q1 + b * q0;
            if (Double.isInfinite(p2) || Double.isInfinite(q2)) {
                if (a != 0.0) {
                    p2 = p1 + (b / a * p0);
                    q2 = q1 + (b / a * q0);
                } else if (b != 0) {
                    p2 = (a / b * p1) + p0;
                    q2 = (a / b * q1) + q0;
                } else {
                    throw new ConvergenceException(ConvergenceException.ERROR,
                        "Continued fraction convergents diverged to +/- " +
                        "infinity.");
                }
            }
            var r = p2 / q2;
            relativeError = Math.abs(r / c - 1.0);
                
            c = p2 / q2;
            p0 = p1;
            p1 = p2;
            q0 = q1;
            q1 = q2;
        }

        if (n >= maxIterations) {
            throw new ConvergenceException(ConvergenceException.ERROR,
                "Continued fraction convergents failed to converge.");
        }

        return c;
	};
	ContinuedFraction.prototype.getA=function(n,x){
		return 1.0;
	};
	ContinuedFraction.prototype.getB=function(n,x){
		var ret;
        var m;
        if (n % 2 == 0) { 
            m = n / 2.0;
            ret = (m * (b - m) * x) /
                ((a + (2 * m) - 1) * (a + (2 * m)));
        } else {
            m = (n - 1.0) / 2.0;
            ret = -((a + m) * (a + b + m) * x) /
                    ((a + (2 * m)) * (a + (2 * m) + 1.0));
        }
        return ret;
	};
	var ret;
    if (Double.isNaN(x) || Double.isNaN(a) || Double.isNaN(b) || (x < 0) ||
        (x > 1) || (a <= 0.0) || (b <= 0.0)) {
        ret = Double.NaN;
    } else if (x > (a + 1.0) / (a + b + 2.0)) {
        ret = 1.0 - Beta.regularizedBeta4(1.0 - x, b, a, epsilon, maxIterations);
    } else {
        var fraction = new ContinuedFraction();
        ret = Math.exp((a * Math.log(x)) + (b * Math.log(1.0 - x)) -
                Math.log(a) - Beta.logBeta2(a, b, epsilon, maxIterations)) *
                1.0 / fraction.evaluate4(x, epsilon, maxIterations);
    }
	return ret;
};

/**
 * Returns the natural logarithm of the beta function B(a, b).
 * @param a the a parameter.
 * @param b the b parameter.
 */
Beta.logBeta=function(a,b){
	return Beta.logBeta2(a, b, Beta.DEFAULT_EPSILON, Integer.MAX_VALUE);
};

/**
 * Returns the natural logarithm of the beta function B(a, b).
 * @param a the a parameter.
 * @param b the b parameter.
 * @param epsilon When the absolute value of the nth item in the series is less 
 * than epsilon the approximation ceases to calculate further elements in the series. 
 * @param maxIterations Maximum number of "iterations" to complete. 
 */
Beta.logBeta2=function(a,b,epsilon,maxIterations){
	var ret;
	if (Double.isNaN(a) || Double.isNaN(b) || (a <= 0.0) || (b <= 0.0)) {
        ret = Double.NaN;
    } else {
        ret = Gamma.logGamma(a) + Gamma.logGamma(b) -
            Gamma.logGamma(a + b);
    }
	
    return ret;
};